package org.finesys.common.netty.websocket.support;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 主动推送数据通道管理
 */
public class NettyChannelMap {
    /**
     * 存放连接的信息
     */
    private final static Map<String, NettySession> channelMap = new ConcurrentHashMap<>();
    /**
     * 单例模式，私有化构造方法。
     */
    private final static NettyChannelMap INSTANCE = new NettyChannelMap();

    /**
     * 获取NettyChannelMap的实例。
     *
     * @return NettyChannelMap的实例。
     */
    public static NettyChannelMap getInstance() {
        return INSTANCE;
    }


    /**
     * 获取当前所有Netty会话的映射关系。
     *
     * @return 一个包含所有Netty会话的映射关系，键是会话ID，值是NettySession对象。
     */
    public Map<String, NettySession> getChannelMap() {
        return channelMap;
    }

    /**
     * 将指定的通道与给定的键关联起来，并存储在通道映射中。
     *
     * @param destination 用于关联通道的键。
     * @param channel     需要与键关联的通道对象。
     */
    public void put(String destination, NettySession channel) {
        channelMap.put(destination, channel);
    }

    /**
     * 将指定的通道与用户名和职位关联起来，并存储在通道映射中。
     * <p>
     * 使用用户名和职位的组合作为键，将通道对象与该键关联起来，以便后续可以通过该键快速检索通道。
     *
     * @param userName    用户名，用于标识通道的所有者。
     * @param destination 目的地，用于进一步区分具有相同用户名的不同通道。
     * @param channel     需要与用户名和职位关联的通道对象。
     */
    public void put(String userName, String destination, NettySession channel) {
        channelMap.put(userName + "/" + destination, channel);
    }

    /**
     * 根据给定的键从通道映射中获取对应的通道对象。
     *
     * @param key 用于检索通道对象的键。
     * @return 与给定键关联的通道对象，如果不存在则返回null。
     */
    public NettySession get(String key) {
        return channelMap.get(key);
    }


    /**
     * 根据用户名和职位获取对应的通道对象。
     * <p>
     * 使用用户名和职位的组合作为键，从通道映射中检索对应的通道对象。
     *
     * @param destination 目的地，用于指定通道对象的目的地信息。
     * @param userName    用户名，用于指定通道对象的所有者。
     * @return 与给定用户名和职位关联的通道对象，如果不存在则返回null。
     */
    public NettySession get(String destination, String userName) {
        String key = userName + "/" + destination;
        return channelMap.get(key);
    }

    /**
     * 从通道映射中移除与指定键关联的通道对象。
     *
     * @param key 用于指定要从通道映射中移除的键。
     */
    public void remove(String key) {
        channelMap.remove(key);
    }

    /**
     * 从通道映射中移除与指定键关联的通道对象。
     *
     * @param key 用于指定要从通道映射中移除的键。
     */
    public void removeUser(String userName) {
        channelMap.keySet().forEach(key -> {
            if (key.startsWith(userName)) {
                channelMap.remove(key);
            }
        });
    }

    /**
     * 从通道映射中移除与指定键关联的通道对象。
     *
     * @param key 用于指定要从通道映射中移除的键。
     */
    public void remove(String destination, String userName) {
        String key = userName + "/" + destination;
        channelMap.remove(key);
    }

    /**
     * 清空通道映射中的所有条目。
     * <p>
     * 此方法将移除通道映射中的所有键值对，使得映射变为空。
     */
    public void clear() {
        channelMap.clear();
    }

    /**
     * 判断通道映射中是否包含指定的键。
     *
     * @param key 要检查的键。
     * @return 如果通道映射中包含指定的键，则返回true；否则返回false。
     */
    public boolean containsKey(String key) {
        return channelMap.containsKey(key);
    }

    public boolean containsKey(String destination, String userName) {
        String key = userName + "/" + destination;
        return channelMap.containsKey(key);
    }

    /**
     * 发送广播消息
     */
    public void sendMessage(Object message) {
        channelMap.values().stream().forEach(channel -> {
            if (channel != null && channel.isActive()) {
                // 发送消息到指定的通道
                channel.getChannel().writeAndFlush(message);
            }
        });
    }

    /**
     * 向指定键对应的通道发送消息。
     * <p>
     * 根据提供的键获取对应的通道，如果通道存在且处于活动状态，则通过该通道发送消息。
     *
     * @param key     用于检索通道的键。
     * @param message 要发送的消息内容。
     */
    public void sendMessage(String destination, Object message) {
        NettySession channel = get(destination);
        if (channel != null && channel.isActive()) {
            // 发送消息到指定的通道
            channel.getChannel().writeAndFlush(message);
        }
    }

    /**
     * 向指定用户和目的地发送消息。
     * <p>
     * 根据提供的目的地和用户名获取对应的通道，如果通道存在且处于活动状态，则通过该通道发送消息。
     *
     * @param destination 目的地标识，用于指定消息发送的目标位置。
     * @param userName    用户名，用于指定接收消息的用户。
     * @param message     要发送的消息内容。
     */
    public void sendMessage(String destination, String userName, Object message) {
        NettySession channel = get(destination, userName);
        if (channel != null && channel.isActive()) {
            // 发送消息到指定的通道
            channel.getChannel().writeAndFlush(message);
        }
    }

}
